﻿''' <summary>
''' 后台报警记录上传
''' </summary>
''' <remarks></remarks>
Public Class BackgroundAlarmData

#Region "Single"

    Private Shared _instance As New BackgroundAlarmData

    Public Shared ReadOnly Property Instance() As BackgroundAlarmData
        Get
            Return _instance
        End Get
    End Property

    Sub New()
        _pi = MainForm.pi
        _bw = New System.ComponentModel.BackgroundWorker()
        _bw.WorkerSupportsCancellation = True
        AddHandler _bw.DoWork, AddressOf DoWork
        AddHandler _bw.RunWorkerCompleted, AddressOf _bw_RunWorkerCompleted


    End Sub

#End Region
    '历史数据的前半页长度（标志）
    Private Const halfPage1 As Byte = 255
    '历史数据的后半页长度（标志）
    Private Const halfPage2 As Byte = 255

    '后台上传的工作线程
    Private _bw As System.ComponentModel.BackgroundWorker

    '启动线程等待过程的Timer

    '历史报警上传完成时间
    Public Event AlarmUploadFinishedEvent As EventHandler

    Private _pi As ProjectItem
    '是否取消后台线程
    Private _cancel As Boolean = False

    '是否正在线程启动准备过程中(即等待上次线程结束)
    Private _isStarting As Boolean = False
    ''' <summary>
    ''' 正在准备运行
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property isStarting() As Boolean
        Get
            Return _isStarting
        End Get
        Set(ByVal value As Boolean)
            _isStarting = value
        End Set
    End Property


    ''' <summary>
    ''' 开始执行后台上传
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Start()

        If _isStarting = True Then  '已经启动线程开始过程
            Exit Sub
        End If

        '_isStarting置为True,表示准备上传
        _isStarting = True

        '等待上次线程的结束(最长等待2分钟)
        For i As Integer = 0 To 1200

            If _bw.IsBusy = False Then
                Exit For
            End If

            System.Threading.Thread.Sleep(100)
            Application.DoEvents()

            If _cancel = True Then
                _isStarting = False
                Exit Sub
            End If
        Next

        '_isStarting置为False,表示准备结束,进入上传状态
        _isStarting = False

        _cancel = False
        _bw.RunWorkerAsync()
    End Sub

    Public Sub StopRead()
        _cancel = True
        If _bw.IsBusy = True Then
            _bw.CancelAsync()
            Application.DoEvents()
        End If

    End Sub
 

    ''' <summary>
    ''' 后台线程的执行方法
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
        Debug.WriteLine("********** 开始历史报警后台上传" & Now.ToLongTimeString())

        '延迟10分钟,然后开始上传
        For i As Integer = 0 To 10 * 60 / g_one1
            If _cancel Then
                Exit Sub
            End If
            System.Threading.Thread.Sleep(1000)
        Next

        Try
            '***********************************************************************
            '2009年06月10日 李吉鹏 修改
            'Select Case _pi.connectType
            Select Case MainForm.pi.connectType

                Case 0 '拨号
                    If g_BackgroundUploadAlarm_Tel Then
                        '#If LSC_DATEUPLOAD_SWICH = "DATE_STARTSTOP_UPLOAD" Then
                        Upload()
                        '#ElseIf LSC_DATEUPLOAD_SWICH = "DATETIME_UPLOAD" Then
                        '                        Upload1()

                        '#End If
                        '上传所有历史数据

                    End If

                Case 1 '直连
                    If g_BackgroundUploadAlarm_Com Then
                        '上传所有历史数据
                        '#If LSC_DATEUPLOAD_SWICH = "DATE_STARTSTOP_UPLOAD" Then
                        Upload()
                        '#ElseIf LSC_DATEUPLOAD_SWICH = "DATETIME_UPLOAD" Then
                        '                        Upload1()

                        '#End If
                    End If


                Case 2 'TCP
                    If g_BackgroundUploadAlarm_Tcp Then
                        '上传所有历史数据
                        '#If LSC_DATEUPLOAD_SWICH = "DATE_STARTSTOP_UPLOAD" Then
                        Upload()
                        '#ElseIf LSC_DATEUPLOAD_SWICH = "DATETIME_UPLOAD" Then
                        '                        Upload1()

                        '#End If
                    End If


            End Select
            'Upload()
            '**************************************************************************************
        Catch ucex As UploadCancelException
            Debug.WriteLine(ucex.GetType().ToString())
        Catch ex As Exception
            Debug.WriteLine("********" & ex.Message)
        End Try
    End Sub

    ''' <summary>
    ''' 历史数据上传结束 
    ''' </summary>
    ''' <remarks></remarks>
    Protected Sub OnUploadFinished()
        If Not _cancel Then
            RaiseEvent AlarmUploadFinishedEvent(Me, New EventArgs())
        End If
    End Sub


    Private Sub _bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
        OnUploadFinished()
    End Sub


    ''' <summary>
    ''' 上传指定压缩机组的历史数据
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Upload()

        Dim cur_netid As Byte
        Dim cur_pid As String
        Dim devtype As Integer

        For Each dti As DevTypeItem In MainForm.pi.DevTypeGroupList

            cur_netid = dti.NetId
            cur_pid = dti.ProjectID

            If _bw.CancellationPending Then
                Debug.WriteLine("################" + _bw.GetHashCode().ToString() + " Exit0")
                Exit For
            End If

            '当前索引页
            Dim curPageIndex As Integer = -1
            Dim curRow As Integer = -1

            '读取历史报警索引页
            Dim dt As DataTable = Nothing

            WaitforBusy()  '未读取报警索引文件前可进行busy等待,而不需要退出
            devtype = DevTypeService.GetdevType(cur_pid, cur_netid)

            Try
                dt = AlarmDataClass.GetAlarmIndexPage(cur_netid, curPageIndex, curRow)
            Catch ex As Exception
                Debug.WriteLine(ex.Message)
                Throw New Exception(" 通讯失败")
                'Exit Sub
                Continue For
            End Try

            If dt Is Nothing Then
                Throw New Exception(" 通讯失败")
                'Exit Sub
                Continue For
            End If

            Dim dtStart, dtEnd As DateTime
            Dim iPage As Integer

            If dt.Rows.Count > 0 And curPageIndex <> -1 Then  '对无报警存在的情况进行保护
                Waitfor()

                '上传当前页
                dtStart = dt.Rows(curPageIndex).Item("StartTime")
                dtEnd = dt.Rows(curPageIndex).Item("EndTime")
                iPage = dt.Rows(curPageIndex).Item("iPage")

                Select Case devtype
                    Case 1
                        AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)
                    Case 16
                        AlarmDataClass.UpdatePageEx16(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)

                End Select


                'Dim iResult As Integer
                'iResult = AlarmDataClass.CheckAlarmData(cur_pid, cur_netid, iPage, dtStart, dtEnd)

                'Waitfor()
                'Select Case iResult
                '    Case -1
                '        '数据没有上传
                '        AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)
                '    Case 0
                '        '数据部分上传
                '        AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)
                '    Case 1
                '        '数据已经上传
                'End Select

                '***************************

                Dim i As Integer
                For i = curPageIndex + 1 To dt.Rows.Count - 1

                    dtStart = dt.Rows(i).Item("StartTime")
                    dtEnd = dt.Rows(i).Item("EndTime")
                    iPage = dt.Rows(i).Item("iPage")


                    'iResult = AlarmDataClass.CheckAlarmData(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                    'If iResult = 1 Then
                    '    '该页已经上传
                    '    Continue For
                    'End If

                    Waitfor()
                    AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                Next

                For i = 0 To curPageIndex - 1
                    dtStart = dt.Rows(i).Item("StartTime")
                    dtEnd = dt.Rows(i).Item("EndTime")
                    iPage = dt.Rows(i).Item("iPage")

                    'iResult = AlarmDataClass.CheckAlarmData(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                    'If iResult = 1 Then
                    '    '该页已经上传
                    '    Continue For
                    'End If

                    Waitfor()
                    AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                Next

            End If
        Next

    End Sub
    ''' <summary>
    ''' 上传指定压缩机组的历史数据
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Upload1()

        Dim cur_netid As Byte
        Dim cur_pid As String

        For Each dti As DevTypeItem In MainForm.pi.DevTypeGroupList

            cur_netid = dti.NetId
            cur_pid = dti.ProjectID

            If _bw.CancellationPending Then
                Debug.WriteLine("################" + _bw.GetHashCode().ToString() + " Exit0")
                Exit For
            End If

            '当前索引页
            Dim curPageIndex As Integer = -1
            Dim curRow As Integer = -1

            '读取历史报警索引页
            Dim dt As DataTable = Nothing

            WaitforBusy()  '未读取报警索引文件前可进行busy等待,而不需要退出

            Try
                dt = AlarmDataClass.GetAlarmIndexPage1(cur_netid, curPageIndex, curRow)
            Catch ex As Exception
                Debug.WriteLine(ex.Message)
                Throw New Exception(" 通讯失败")
                'Exit Sub
                Continue For
            End Try

            If dt Is Nothing Then
                Throw New Exception(" 通讯失败")
                'Exit Sub
                Continue For
            End If

            Dim dtStart, dtEnd As DateTime
            Dim iPage As Integer

            If dt.Rows.Count > 0 And curPageIndex <> -1 Then  '对无报警存在的情况进行保护
                Waitfor()

                '上传当前页
                dtStart = dt.Rows(curPageIndex).Item("StartTime")
                dtEnd = dt.Rows(curPageIndex).Item("EndTime")
                iPage = dt.Rows(curPageIndex).Item("iPage")

                AlarmDataClass.UpdatePage1(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)

                'Dim iResult As Integer
                'iResult = AlarmDataClass.CheckAlarmData(cur_pid, cur_netid, iPage, dtStart, dtEnd)

                'Waitfor()
                'Select Case iResult
                '    Case -1
                '        '数据没有上传
                '        AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)
                '    Case 0
                '        '数据部分上传
                '        AlarmDataClass.UpdatePage(cur_pid, cur_netid, iPage, dtStart, dtEnd, curRow)
                '    Case 1
                '        '数据已经上传
                'End Select

                '***************************

                Dim i As Integer
                For i = curPageIndex + 1 To dt.Rows.Count - 1

                    dtStart = dt.Rows(i).Item("StartTime")
                    dtEnd = dt.Rows(i).Item("EndTime")
                    iPage = dt.Rows(i).Item("iPage")


                    'iResult = AlarmDataClass.CheckAlarmData(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                    'If iResult = 1 Then
                    '    '该页已经上传
                    '    Continue For
                    'End If

                    Waitfor()
                    AlarmDataClass.UpdatePage1(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                Next

                For i = 0 To curPageIndex - 1
                    dtStart = dt.Rows(i).Item("StartTime")
                    dtEnd = dt.Rows(i).Item("EndTime")
                    iPage = dt.Rows(i).Item("iPage")

                    'iResult = AlarmDataClass.CheckAlarmData(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                    'If iResult = 1 Then
                    '    '该页已经上传
                    '    Continue For
                    'End If

                    Waitfor()
                    AlarmDataClass.UpdatePage1(cur_pid, cur_netid, iPage, dtStart, dtEnd)
                Next

            End If
        Next

    End Sub

    ''' <summary>
    ''' 暂停一段时间
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Waitfor()

        '防止上位机与下位机的历史报警时间记录不一致导致的更新记录出错的问题
        If g_busy OrElse g_dbbackup Then
            '其它地方正在修改参数或者前台上传时停止后台上传
            Throw New UploadCancelException()
        End If

        If _cancel Then
            '取消上传
            Throw New UploadCancelException()
        End If

        System.Threading.Thread.Sleep(200)

    End Sub


    ''' <summary>
    ''' 暂停等待busy一段时间
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub WaitforBusy()

        If _cancel Then
            '取消上传
            Throw New UploadCancelException()
        End If

        '其它地方正在修改参数或者前台上传时暂停后台上传
        While (g_busy OrElse g_dbbackup)
            System.Threading.Thread.Sleep(100)

            If _cancel Then
                '取消上传
                Throw New UploadCancelException()
            End If

        End While

    End Sub



    ''' <summary>
    ''' 读取指定页的数据
    ''' </summary>
    ''' <param name="netID">PLC站号</param>
    ''' <param name="iPage">页地址</param>
    ''' <param name="tryCount">读取数据失败时,连续尝试读取得此时</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function UploadOnePage(ByVal netID As Integer, ByVal iPage As Integer, ByVal tryCount As Integer) As Byte()
        If tryCount < 1 Then
            tryCount = 1
        End If

        Dim buf(512) As Byte
        Dim b1() As Byte = Nothing

        Dim iTry As Integer

        '读取前半页
        iTry = 1
        While b1 Is Nothing AndAlso iTry <= tryCount
            If _cancel Then
                '取消上传
                Throw New UploadCancelException()
            End If

            iTry += 1
            b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.WordWrite, iPage, 256)
        End While
        If b1 Is Nothing Then
            Return Nothing
        End If
        b1.CopyTo(buf, 0)

        '读取前后页
        iTry = 1
        While b1 Is Nothing AndAlso iTry <= tryCount

            If _cancel Then
                '取消上传
                Throw New UploadCancelException()
            End If

            iTry += 1
            b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.WordWrite, iPage, 256)
        End While
        If b1 Is Nothing Then
            Return Nothing
        End If
        b1.CopyTo(buf, 256)

        Return buf
    End Function


    ''' <summary>
    ''' 判断指定位是否为1
    ''' </summary>
    ''' <param name="b"></param>
    ''' <param name="i"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GetBit(ByVal b As Byte, ByVal i As Integer) As Byte
        Dim iTest As Byte
        iTest = 2 ^ i

        Dim result As Byte
        result = b And iTest

        If result > 0 Then
            result = 1
        End If

        Return result
    End Function
 

End Class
